﻿// ------------------------------------------------------------------------------------------------
//  <copyright file="IntTable.cs" company="Iveely">
//    Copyright (c) Iveely Liu.  All rights reserved.
//  </copyright>
//  
//  <Create Time>
//    03/02/2013 21:59 
//  </Create Time>
//  
//  <contact owner>
//    liufanping@iveely.com 
//  </contact owner>
//  -----------------------------------------------------------------------------------------------

#region

using System;
using System.Collections;
using System.Linq.Expressions;
using System.Runtime.Serialization;

#endregion

namespace IveelySE.NLP.Common.DataStructure.Table
{
    /// <summary>
    ///   Int类型哈希表
    ///   主要用于Key存储关键字，对值有累加操作的哈希表
    /// </summary>
    [Serializable]
    public class IntTable<TKey, TValue> : Hashtable
    {
        #region 公有方法

        protected IntTable(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
        }

        public IntTable()
        {
        }

        /// <summary>
        ///   添加关键字
        /// </summary>
        /// <param name="key"> 关键字 </param>
        /// <param name="value"> 值（遇到重复值，则累加） </param>
        public void Add(TKey key, TValue value, bool accumulate = true)
        {
            if(this.ContainsKey(key) && accumulate)
            {
                this[key] = Add(ConvertType(this[key]), value);
            }
            else
            {
                this[key] = value;
            }
        }

        /// <summary>
        ///   批量插入值
        /// </summary>
        ///// <param name="keys">关键字数组</param>
        public void Add(TKey[] keys)
        {
            foreach(TKey key in keys)
            {
                this.Add(key, ConvertType(1));
            }
        }

        #endregion

        #region 私有方法

        /// <summary>
        ///   泛型数据类型转换
        /// </summary>
        /// <param name="value"> 传入需要转换的值 </param>
        /// <param name="defaultValue"> 默认值 </param>
        /// <returns> </returns>
        private TValue ConvertType(object value)
        {
            return (TValue) ConvertToT(value);
        }


        /// <summary>
        ///   转换数据类型
        /// </summary>
        /// <typeparam name="T"> 自定义数据类型 </typeparam>
        /// <param name="myvalue"> 传入需要转换的值 </param>
        /// <returns> </returns>
        private object ConvertToT(object myvalue)
        {
            TypeCode typeCode = Type.GetTypeCode(typeof(TValue));
            string value = myvalue.ToString();
            switch(typeCode)
            {
                case TypeCode.Boolean:
                    bool flag = false;
                    if(bool.TryParse(value, out flag))
                        return flag;
                    break;
                case TypeCode.Char:
                    char c;
                    if(Char.TryParse(value, out c))
                        return c;
                    break;
                case TypeCode.SByte:
                    sbyte s = 0;
                    if(SByte.TryParse(value, out s))
                        return s;
                    break;
                case TypeCode.Byte:
                    byte b = 0;
                    if(Byte.TryParse(value, out b))
                        return b;
                    break;
                case TypeCode.Int16:
                    Int16 i16 = 0;
                    if(Int16.TryParse(value, out i16))
                        return i16;
                    break;
                case TypeCode.UInt16:
                    UInt16 ui16 = 0;
                    if(UInt16.TryParse(value, out ui16))
                        return ui16;
                    break;
                case TypeCode.Int32:
                    int i = 0;
                    if(Int32.TryParse(value, out i))
                        return i;
                    break;
                case TypeCode.UInt32:
                    UInt32 ui32 = 0;
                    if(UInt32.TryParse(value, out ui32))
                        return ui32;
                    break;
                case TypeCode.Int64:
                    Int64 i64 = 0;
                    if(Int64.TryParse(value, out i64))
                        return i64;
                    break;
                case TypeCode.UInt64:
                    UInt64 ui64 = 0;
                    if(UInt64.TryParse(value, out ui64))
                        return ui64;
                    break;
                case TypeCode.Single:
                    Single single = 0;
                    if(Single.TryParse(value, out single))
                        return single;
                    break;
                case TypeCode.Double:
                    double d = 0;
                    if(Double.TryParse(value, out d))
                        return d;
                    break;
                case TypeCode.Decimal:
                    decimal de = 0;
                    if(Decimal.TryParse(value, out de))
                        return de;
                    break;
                case TypeCode.DateTime:
                    DateTime dt;
                    if(DateTime.TryParse(value, out dt))
                        return dt;
                    break;
                case TypeCode.String:
                    if(value.Length == 0)
                        return "";
                    return value;
            }
            throw new ArgumentNullException("myvalue", "不能为Empty,Object,DBNull");
        }

        /// <summary>
        ///   泛型相加
        /// </summary>
        /// <param name="num1"> </param>
        /// <param name="num2"> </param>
        /// <returns> </returns>
        private object Add(TValue num1, TValue num2)
        {
            //TODO:Fix ,should use lambda
            return int.Parse(num1.ToString()) + int.Parse(num2.ToString());
            //var para1 = Expression.Parameter(typeof(TValue), "p1");
            //var para2 = Expression.Parameter(typeof(TValue), "p2");
            //var expsAdd = Expression.Lambda<Func<TValue, TValue, TValue>>(Expression.Add(para1, para2));
            //Func<TValue, TValue, TValue> fun = expsAdd.Compile();
            //return fun(num1, num2);
        }

        #endregion
    }
}